/*
 Trabajo Practico 2 Ejercicio 3
 Entrega número: 1

 - Integrantes:
	- Martinez, Guillermo	DNI: 34510461
	- Meli, Marcos		DNI: 31832759
	- Reyes, Leandro	DNI: 34213699
	- Rodriguez, Lucas	DNI: 34265017
	- Cortez, Martin	DNI: 30440023
*/

#include "padre.h"
#include "../tools/tools.h"

int cantHijos = SINHIJOS;
int cantHijosFinalizados = 0;
//Array que guardara los pid de los hijos.
int hijos[MAXHIJOS];

void handler_padre(int no_senal, siginfo_t *info, void *noseusa) {
	int pid, i, senialdehijo = FALSE;
	char description[STR_SIZE + 1];
	//Verifico que la señal recibida sea de un proceso hijo.
	for(i = 0; i < cantHijos ; i++)
		if(hijos[i] == info->si_pid)
			senialdehijo = TRUE;

	if(!senialdehijo){
		//Si la señal no es de un hijo y es SIGINT, SIGTERM, SIGUSR1 o SIGUSR2 son manejadas, si no ignoradas.
		if(info->si_signo == SIGINT || info->si_signo == SIGTERM){
			while(cantHijos > SINHIJOS && cantHijosFinalizados < cantHijos){
				kill(hijos[cantHijosFinalizados], SIGINT);
				wait(NULL);
				cantHijosFinalizados++;
			}
			exit(0);
		}
		//Crea nuevos procesos hijos.
		if(info->si_signo == SIGUSR1){
			if(cantHijos < MAXHIJOS){
				pid = fork();
				if(pid == 0){
					hijo();
				}else{
					printf("Padre %d > Creando hijo nro %d con PID %d.\n", getpid(), cantHijos+1, pid);
					hijos[cantHijos] = pid;
					cantHijos++;
				}
			}else
				printf("Padre %d > Se ha alcanzado el limite de %d procesos hijos.\n", getpid(), cantHijos);
		}
		
		//Elimina procesos hijos en orden fifo.
		if(info->si_signo == SIGUSR2){
			if(cantHijos > SINHIJOS && cantHijosFinalizados < cantHijos){
				if(kill(hijos[cantHijosFinalizados], SIGINT) == 0){
					printf("Padre %d > Eliminando hijo nro %d con PID %d.\n", getpid()
											, cantHijosFinalizados+1
											, hijos[cantHijosFinalizados]);
					cantHijosFinalizados++;
				}
			}
		}
	}else{
		//Se verifica si un hijo termino o simplemente envio una señal SIGCHLD.
		if(info->si_signo == SIGCHLD && info->si_code == CLD_EXITED )
			wait(NULL);
		else{
			//Si la señal es de un hijo se muestra por pantalla que señal envio y que hijo fue.
			GetString( description, STR_SIZE, info->si_signo );
			printf("Padre %d > Se recibió la señal %s del proceso %d.\n", getpid(), description, info->si_pid);
		}
	}
}

void padre () {
	struct sigaction sa;
	int i;
	printf("Padre %d > Iniciando proceso padre con PID %d.\n", getpid(), getpid());
	sa.sa_flags=SA_SIGINFO;
	sa.sa_sigaction=&handler_padre; 
	//Manejo todas las señales con sigaction.
	for(i = SIGHUP ; i <= SIGRTMAX ; i++)
		sigaction(i, &sa, NULL);
	while(1)
		pause();
}